﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Msdn5.Framework
{
    /// <summary>
    /// 一个关于DateTime各种扩展
    /// </summary>
    public static class DateTimeExHelper
    {
     

        /// <summary>
        /// 获取传入时间本月第一天和最后一天DatetimeEx对象
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <returns>DatetimeEx对象</returns>
        public static DatetimeEx GetFirstAndLastDateTime(this DateTime dt)
        {
            int monthDay = DateTime.DaysInMonth(dt.Year, dt.Month);
            DateTime d1 = new DateTime(dt.Year, dt.Month, 1, 00, 00, 00);
            DateTime d2 = new DateTime(dt.Year, dt.Month, monthDay, 23, 59, 59);
            DatetimeEx dtex = new DatetimeEx();
            dtex.StartTime = d1;
            dtex.EndTime = d2;
            dtex.StartTimeStr = d1.ToStartStr();
            dtex.EndTimeStr = d2.ToEndStr();
            return dtex;
        }

        /// <summary>
        /// 获取未来几日的集合(今天至未来间所有的日期)
        /// 注意,默认时间包含今日.(第一天为今天) 
        /// 只取日期部分GetFutureDays().Select(v=>v.StartTimeDate).ToArray()
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <param name="day">默认为7天后</param>
        /// <returns>包含今日至未来几日的集合</returns>
        public static List<DatetimeEx> GetFutureDays(this DateTime dt, int day = 7)
        {
            List<DatetimeEx> daylist = new List<DatetimeEx>();
            DateTime dtnow = dt;
            DateTime dtlast = DateTime.Now.Date.AddDays(day);
            for (; dtnow.CompareTo(dtlast) < 0;)
            {
                daylist.Add(dtnow.ToDateTimeEx());
                dtnow = dtnow.AddDays(1);
            }
            daylist.Add(dtlast.ToDateTimeEx());
            return daylist;
        }

        /// <summary>
        /// 获取过去几日的集合(n天前至今所有的日期)
        /// 注意,集合包含今日.(最后一天为今天) 
        /// 只取日期部分 GetPastDays().Select(v=>v.StartTimeDate).ToArray()
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <param name="day">默认为7天前</param>
        /// <returns>过去几日至今日的集合</returns>
        public static List<DatetimeEx> GetPastDays(this DateTime dt, int day = 7)
        {
            List<DatetimeEx> daylist = new List<DatetimeEx>();
            DateTime dtnow = dt;
            day *= -1;
            DateTime dtlast = dt.AddDays(day);
            for (; dtlast.CompareTo(dtnow) < 0;)
            {
                daylist.Add(dtlast.ToDateTimeEx());
                dtlast = dtlast.AddDays(1);
            }
            daylist.Add(dt.ToDateTimeEx());
            return daylist;
        }

        /// <summary>
        /// 判断一个时间是否为正常时间格式
        /// 如果是直接返回DateTime对象
        /// </summary>
        /// <param name="StrDate">时间字符串</param>
        /// <param name="dt">转换后的DateTime对象</param>
        /// <returns>是否转换成功</returns>
        public static bool IsDateTime(this string StrDate, out DateTime dt)
        {
            return DateTime.TryParse(StrDate, out dt);
        }

        /// <summary>
        /// 判断当前时间是否在两个时间区间内,
        /// 是两个区间内则返回true,否则false
        /// </summary>
        /// <param name="dt">如果不传则为当前时间</param>
        /// <param name="dt1">00:00:00</param>
        /// <param name="dt2">23:59:59</param> 
        /// <returns></returns>
        public static bool TimeScope(this DateTime dt, string dt1 = "00:00:00", string dt2 = "23:59:59")
        {
            if (dt == default)
            {
                dt = DateTime.Now;
            }
            DateTime dtx1 = DateTime.Parse(dt1);
            DateTime dtx2 = DateTime.Parse(dt2);
            TimeSpan ts1 = dtx1.Subtract(dt);
            TimeSpan ts2 = dtx2.Subtract(dt);
            if (ts1.TotalSeconds < 0 && ts2.TotalSeconds > 1)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 判断一个时间是否
        /// 大于等于开始时间
        /// 小于等于结束时间
        /// true表明正确
        /// </summary>
        /// <param name="dt">一个时间对象</param>
        /// <param name="start">开始时间</param>
        /// <param name="end">结束时间</param> 
        /// <returns>是否为正确时间</returns>
        public static bool TimeScope(this DateTime dt, DateTime start, DateTime end)
        {
            if (dt == default)
            {
                dt = DateTime.Now;
            }
            if (dt >= start && dt <= end)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 时间戳转为时间对象(自动+8小时)
        /// </summary>
        /// <param name="timeStamp">Unix时间戳格式</param>
        /// <returns>时间对象</returns>
        public static DateTime TimeStampToDateTime(this string timeStamp)
        {

            DateTime startTime = TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1), TimeZoneInfo.Local); // 当地时区
            if (long.TryParse(timeStamp, out long ts))
            {
                if (timeStamp.Length == 10)
                {
                    return startTime.AddHours(8).AddSeconds(ts);
                }
                else
                {
                    return startTime.AddHours(8).AddMilliseconds(ts);
                }
            }
            return default(DateTime);
        }

        /// <summary>
        /// 一个字符串时间转换成DateTime对象
        /// 转换失败则返回default
        /// </summary>
        /// <param name="StrDate">字符串时间</param>
        /// <returns>转换后的时间对象</returns>
        public static DateTime ToDateTime(this string StrDate)
        {
            DateTime dt;
            if (!DateTime.TryParse(StrDate, out dt))
            {
                dt = default;//如果无法转换则返回default
            }
            return dt;
        }

        /// <summary>
        /// 获取一个包含开始与结束时间的扩展对象
        /// </summary>
        /// <param name="StartDate">开始时间字符串</param>
        /// <param name="EndDate">结束时间字符串</param>
        /// <returns>包含开始与结束时间的扩展对象</returns>
        public static DatetimeEx ToDatetimeEx(string StartDate, string EndDate)
        {
            DatetimeEx dtEX = new DatetimeEx();
            //开始时间
            dtEX.StartTime = StartDate.ToDateTime().ToStartTime();
            dtEX.StartTimeStr = dtEX.StartTime.ToStr();
            //结束时间
            dtEX.EndTime = EndDate.ToDateTime().ToEndTime();
            dtEX.EndTimeStr = dtEX.EndTime.ToStr();
            return dtEX;
        }

        /// <summary>
        /// 一个字符串时间转换成DateTimeEx对象
        /// DateTimeEx 包含开始时间,结束时间
        /// </summary>
        /// <param name="StrDateTime"></param>
        /// <returns></returns>
        public static DatetimeEx ToDateTimeEx(this string StrDateTime)
        {
            DatetimeEx dtEX = new DatetimeEx();
            //开始时间
            dtEX.StartTime = StrDateTime.ToDateTime().ToStartTime();
            dtEX.StartTimeStr = dtEX.StartTime.ToStr();
            //结束时间
            dtEX.EndTime = StrDateTime.ToDateTime().ToEndTime();
            dtEX.EndTimeStr = dtEX.EndTime.ToStr();
            return dtEX;
        }

        /// <summary>
        /// DateTime对象转换成DateTimeEx对象
        /// DateTimeEx 包含开始时间,结束时间
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <returns>包含开始与结束时间的扩展对象</returns>
        public static DatetimeEx ToDateTimeEx(this DateTime dt)
        {
            DatetimeEx dtEX = new DatetimeEx();
            //开始时间
            dtEX.StartTime = dt.ToStartTime();
            dtEX.StartTimeStr = dtEX.StartTime.ToStr();
            //结束时间
            dtEX.EndTime = dt.ToEndTime();
            dtEX.EndTimeStr = dtEX.EndTime.ToStr();
            return dtEX;
        }

        /// <summary>
        /// 获取当前的结束时间字符串
        /// yyyy-MM-dd 23:59:59
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <returns>返回当前的结束时间字符串</returns>
        public static string ToEndStr(this DateTime dt)
        {
            return dt.ToEndTime().ToStr();
        }

        /// <summary>
        /// 获取当前的结束时间对象
        /// yyyy-MM-dd 23:59:59
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <returns>返回当前的结束时间对象</returns>
        public static DateTime ToEndTime(this DateTime dt)
        {
            return DateTime.Parse($"{dt.ToShortDateString()} 23:59:59");
        }

        /// <summary>
        /// 返回时间的yyyy-MM-dd
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <returns>yyyy-MM-dd</returns>
        public static string ToShortDateStr(this DateTime dt)
        {
            return dt.ToShortDateString().Replace("/", "-");
        }

        /// <summary>
        /// 获取当前的开始时间字符串
        /// yyyy-MM-dd 00:00:00
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <returns>返回当前的开始时间字符串</returns>
        public static string ToStartStr(this DateTime dt)
        {
            return dt.ToStartTime().ToStr();
        }

        /// <summary>
        /// 获取当前的开始时间对象
        /// yyyy-MM-dd 00:00:00
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <returns>返回当前的开始时间对象</returns>
        public static DateTime ToStartTime(this DateTime dt)
        {
            return DateTime.Parse($"{dt.ToShortDateString()} 00:00:00");
        }
        /// <summary>
        /// 获取仅时间的标准字符串(秒级)
        /// 格式HH:mm:ss
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <returns>HH:mm:ss格式的字符串</returns>
        public static string ToShortTimeStr(this DateTime dt)
        {
            return $"{dt.Hour}:{dt.Minute}:{dt.Second}";
        }
        /// <summary>
        /// 获取当前时间的标准字符串(带标准符号 秒级)
        /// 格式 yyyy-MM-dd HH:mm:ss
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <returns>返回yyyy-MM-dd HH:mm:ss格式的字符串</returns>
        public static string ToStr(this DateTime dt)
        {
            return dt.ToString("yyyy-MM-dd HH:mm:ss");
        }
        /// <summary>
        /// 获取当前时间的标准字符串(带标准符号 毫秒级)
        /// 格式 yyyy-MM-dd HH:mm:ss.fff
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <returns>返回yyyy-MM-dd HH:mm:ss.fff格式的字符串</returns>
        public static string ToStrMilliSecond(this DateTime dt)
        {
            return dt.ToString("yyyy-MM-dd HH:mm:ss.fff");
        }

        /// <summary>  
        /// 指定时间转换时间戳/秒(10位) 
        /// </summary>  
        /// <param name="dt">传入的时间</param>
        /// <returns>10位时间戳</returns>  
        public static string ToTimeStamp10(this DateTime dt)
        {
            return TimeSpan.FromTicks(dt.ToUniversalTime().Ticks - new DateTime(1970, 1, 1, 0, 0, 0, 0).Ticks).TotalSeconds.ToString("0");
        }

        /// <summary>
        /// 指定时间转换时间戳/毫秒(13位)
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <returns>13位时间戳</returns>
        public static string ToTimeStamp13(this DateTime dt)
        {
            return TimeSpan.FromTicks(dt.ToUniversalTime().Ticks - new DateTime(1970, 1, 1, 0, 0, 0, 0).Ticks).TotalMilliseconds.ToString("0");

        }

        /// <summary>
        ///  获取传入时间的yyyyMMddHHmmss(无符号 秒级)
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <returns>yyyyMMddHHmmss</returns>
        public static string ToUStr(this DateTime dt)
        {
            return dt.ToString("yyyyMMddHHmmss");
        }
        /// <summary>
        ///  获取传入时间的yyyyMMddHHmmssfff(无符号 毫秒级)
        /// </summary>
        /// <param name="dt">传入的时间</param>
        /// <returns>yyyyMMddHHmmssfff</returns>
        public static string ToUStrEx(this DateTime dt)
        {
            return dt.ToString("yyyyMMddHHmmssfff");
        }
    }
    /// <summary>
    /// 包含一个开始时间和结束时间的扩展对象
    /// 含Datetime对象与字符串
    /// 开始时间格式 yyyy-MM-dd 00:00:00
    /// 结束时间格式 yyyy-MM-dd 23:59:59
    /// </summary>
    public class DatetimeEx
    {
        /// <summary>
        /// 结束时间
        /// yyyy-MM-dd 23:59:59
        /// </summary>
        public DateTime EndTime;

        /// <summary>
        /// 开始时间
        /// yyyy-MM-dd 00:00:00
        /// </summary>
        public DateTime StartTime;
        /// <summary>
        /// 结束时间日期部分
        /// yyyy-MM-dd
        /// </summary>
        public string EndTimeDate { get => EndTime.ToShortDateStr(); }

        /// <summary>
        /// 结束时间字符串
        /// yyyy-MM-dd 23:59:59
        /// </summary>
        public string EndTimeStr { get; set; }

        /// <summary>
        /// 结束时间时间部分
        /// HH:mm:ss
        /// </summary>
        public string EndTimeTime { get => EndTime.ToShortTimeString(); }

        /// <summary>
        /// 开始时间日期部分
        /// yyyy-MM-dd
        /// </summary>
        public string StartTimeDate { get => StartTime.ToShortDateStr(); }

        /// <summary>
        /// 开始时间字符串
        /// yyyy-MM-dd 00:00:00
        /// </summary>
        public string StartTimeStr { get; set; }
        /// <summary>
        /// 开始时间时间部分
        /// HH:mm:ss
        /// </summary>
        public string StartTimeTime { get => StartTime.ToShortTimeString(); }
    }
}
